﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Web;

namespace LuceneApiServerLib
{
    /// <summary>
    ///     网络工具类。
    /// </summary>
    public sealed class WebUtils
    {
        private const string ContentEncoding = "iso-8859-1";
        private int _timeout = 100000;
        public Encoding UrlEncoding = Encoding.UTF8;

        /// <summary>
        ///     请求与响应的超时时间
        /// </summary>
        public int Timeout
        {
            get { return _timeout; }
            set { _timeout = value; }
        }

        /// <summary>
        ///     执行HTTP POST请求。
        /// </summary>
        /// <param name="url">请求地址</param>
        /// <param name="parameters">请求参数</param>
        /// <returns>HTTP响应</returns>
        public string DoPost(string url, IDictionary<string, string> parameters)
        {
            var req = GetWebRequest(url, "POST");
            req.ContentType = "application/x-www-form-urlencoded;charset=utf-8";

            var postData = Encoding.UTF8.GetBytes(BuildQuery(parameters));
            var reqStream = req.GetRequestStream();
            reqStream.Write(postData, 0, postData.Length);
            reqStream.Close();

            var rsp = (HttpWebResponse) req.GetResponse();
            var encoding = Encoding.GetEncoding(rsp.CharacterSet);
            return GetResponseAsString(rsp, encoding);
        }

        /// <summary>
        ///     执行HTTP GET请求。
        /// </summary>
        /// <param name="url">请求地址</param>
        /// <param name="parameters">请求参数</param>
        /// <returns>HTTP响应</returns>
        public string DoGet(string url, IDictionary<string, string> parameters)
        {
            if (parameters != null && parameters.Count > 0)
            {
                if (url.Contains("?"))
                {
                    url = url + "&" + BuildQuery(parameters);
                }
                else
                {
                    url = url + "?" + BuildQuery(parameters);
                }
            }

            var req = GetWebRequest(url, "GET");
            req.ContentType = "application/x-www-form-urlencoded;charset=utf-8";

            var rsp = (HttpWebResponse) req.GetResponse();
            var encoding = Encoding.GetEncoding(rsp.CharacterSet);
            return GetResponseAsString(rsp, encoding);
        }

        public bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain,
            SslPolicyErrors errors)
        {
            //直接确认，否则打不开
            return true;
        }

        public HttpWebRequest GetWebRequest(string url, string method)
        {
            HttpWebRequest req = null;
            if (url.Contains("https"))
            {
                ServicePointManager.ServerCertificateValidationCallback = CheckValidationResult;
                req = (HttpWebRequest) WebRequest.CreateDefault(new Uri(url));
            }
            else
            {
                req = (HttpWebRequest) WebRequest.Create(url);
            }

            req.ServicePoint.Expect100Continue = false;
            req.Method = method;
            req.KeepAlive = true;
            req.Timeout = _timeout;

            return req;
        }

        /// <summary>
        ///     把响应流转换为文本。
        /// </summary>
        /// <param name="rsp">响应流对象</param>
        /// <param name="encoding">编码方式</param>
        /// <returns>响应文本</returns>
        public string GetResponseAsString(HttpWebResponse rsp, Encoding encoding)
        {
            Stream stream = null;
            StreamReader reader = null;

            try
            {
                // 以字符流的方式读取HTTP响应
                stream = rsp.GetResponseStream();
                reader = new StreamReader(stream, encoding);
                return reader.ReadToEnd();
            }
            finally
            {
                // 释放资源
                if (reader != null) reader.Close();
                if (stream != null) stream.Close();
                if (rsp != null) rsp.Close();
            }
        }

        /// <summary>
        ///     组装GET请求URL。
        /// </summary>
        /// <param name="url">请求地址</param>
        /// <param name="parameters">请求参数</param>
        /// <returns>带参数的GET请求URL</returns>
        public string BuildGetUrl(string url, IDictionary<string, string> parameters)
        {
            if (parameters != null && parameters.Count > 0)
            {
                if (url.Contains("?"))
                {
                    url = url + "&" + BuildQuery(parameters);
                }
                else
                {
                    url = url + "?" + BuildQuery(parameters);
                }
            }
            return url;
        }

        /// <summary>
        ///     组装普通文本请求参数。
        /// </summary>
        /// <param name="parameters">Key-Value形式请求参数字典</param>
        /// <returns>URL编码后的请求数据</returns>
        public string BuildQuery(IDictionary<string, string> parameters)
        {
            var postData = new StringBuilder();
            var hasParam = false;

            var dem = parameters.GetEnumerator();
            while (dem.MoveNext())
            {
                var name = dem.Current.Key;
                var value = dem.Current.Value;
                // 忽略参数名或参数值为空的参数
                if (!string.IsNullOrEmpty(name) && !string.IsNullOrEmpty(value))
                {
                    if (hasParam)
                    {
                        postData.Append("&");
                    }

                    postData.Append(name);
                    postData.Append("=");
                    postData.Append(HttpUtility.UrlEncode(value, UrlEncoding));
                    hasParam = true;
                }
            }

            return postData.ToString();
        }

        public string DoPostWithPicture(string url, string filepath, string paraName,
            IDictionary<string, string> parameters)
        {
            var appendUrl = BuildGetUrl(url, parameters);
            var request = (HttpWebRequest) WebRequest.Create(appendUrl);

            //request.PreAuthenticate = true;
            request.AllowWriteStreamBuffering = true;
            request.Method = "POST";
            //request.UserAgent = "Jakarta Commons-HttpClient/3.1";
            request.Timeout = _timeout;
            var bytes = GetContentsBytes(request, filepath, paraName, null);

            var requestStream = request.GetRequestStream();
            try
            {
                requestStream.Write(bytes, 0, bytes.Length);
            }
            finally
            {
                requestStream.Close();
            }

            string result = null;
            WebResponse wresp = null;
            try
            {
                wresp = request.GetResponse();
                var stream2 = wresp.GetResponseStream();
                var reader2 = new StreamReader(stream2);

                result = reader2.ReadToEnd();
            }
            finally
            {
                if (wresp != null)
                {
                    wresp.Close();
                    wresp = null;
                }
            }
            return result;
        }

        private byte[] GetContentsBytes(WebRequest request, string filepath, string paraName,
            IDictionary<string, string> nvc)
        {
            var boundary = Guid.NewGuid().ToString();
            var header = string.Format("--{0}", boundary);
            var footer = string.Format("--{0}--", boundary);

            var contents = new StringBuilder();
            request.ContentType = string.Format("multipart/form-data; boundary={0}", boundary);
            if (nvc != null)
            {
                foreach (var key in nvc.Keys)
                {
                    contents.AppendLine(header);
                    contents.AppendLine(string.Format("Content-Disposition: form-data; name=\"{0}\"", key));
                    contents.AppendLine("Content-Type: text/plain; charset=US-ASCII");
                    contents.AppendLine("Content-Transfer-Encoding: 8bit");
                    contents.AppendLine();
                    contents.AppendLine(nvc[key]);
                }
            }

            contents.AppendLine(header);
            var fileHeader = string.Format("Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"", paraName,
                filepath);
            var fileData = Encoding.GetEncoding(ContentEncoding).GetString(File.ReadAllBytes(@filepath));

            contents.AppendLine(fileHeader);
            contents.AppendLine("Content-Type: application/octet-stream; charset=UTF-8");
            contents.AppendLine("Content-Transfer-Encoding: binary");
            contents.AppendLine();
            contents.AppendLine(fileData);

            contents.AppendLine(footer);

            var bytes = Encoding.GetEncoding(ContentEncoding).GetBytes(contents.ToString());
            request.ContentLength = bytes.Length;
            return bytes;
        }

        /// <summary>
        ///     Post方式上传图片。
        /// </summary>
        /// <param name="url"></param>
        /// <param name="file"></param>
        /// <param name="paramName"></param>
        /// <param name="contentType"></param>
        /// <param name="nvc"></param>
        /// <returns></returns>
        public string HttpUploadFile(string url, string file, string paramName, string contentType,
            IDictionary<string, string> nvc)
        {
            var fileStream = new FileStream(file, FileMode.Open, FileAccess.Read);

            var read = new BinaryReader(fileStream);

            var count = (int) fileStream.Length;

            var buffer = new byte[count];

            read.Read(buffer, 0, buffer.Length);

            var msg = Encoding.UTF8.GetString(buffer);

            var postData = BuildQuery(nvc);

            var data = Encoding.UTF8.GetBytes(postData + "&" + paramName + "=" + msg);
            var req = GetWebRequest(url, "POST");
            req.ContentType = "multipart/form-data;";
            req.ContentLength = data.Length;

            var reqStream = req.GetRequestStream();
            reqStream.Write(data, 0, data.Length);
            reqStream.Close();

            var rsp = (HttpWebResponse) req.GetResponse();
            var encoding = Encoding.GetEncoding(rsp.CharacterSet);
            return GetResponseAsString(rsp, encoding);
        }
    }
}